package com.particles.particles.util;

import android.util.Log;

import static android.opengl.GLES20.GL_COMPILE_STATUS;
import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
import static android.opengl.GLES20.GL_LINK_STATUS;
import static android.opengl.GLES20.GL_VALIDATE_STATUS;
import static android.opengl.GLES20.GL_VERTEX_SHADER;
import static android.opengl.GLES20.glAttachShader;
import static android.opengl.GLES20.glCompileShader;
import static android.opengl.GLES20.glCreateProgram;
import static android.opengl.GLES20.glCreateShader;
import static android.opengl.GLES20.glDeleteProgram;
import static android.opengl.GLES20.glDeleteShader;
import static android.opengl.GLES20.glGetProgramInfoLog;
import static android.opengl.GLES20.glGetProgramiv;
import static android.opengl.GLES20.glGetShaderInfoLog;
import static android.opengl.GLES20.glGetShaderiv;
import static android.opengl.GLES20.glLinkProgram;
import static android.opengl.GLES20.glShaderSource;
import static android.opengl.GLES20.glValidateProgram;

/**
 * Created by Cuckoo322 on 4/9/2017.
 */

public class ShaderHelper {

    public static final String TAG = "ShaderHelper";

    public static int compileVertexShader(String shaderCode) {
        return compileShader(GL_VERTEX_SHADER, shaderCode);
    }

    public static int compileFragmentShader(String shaderCode) {
        return compileShader(GL_FRAGMENT_SHADER, shaderCode);
    }

    private static int compileShader(int type, String shaderCode) {
        //创建一个新的着色器对象并将id保存起来
        final int shaderObjectId = glCreateShader(type);

        if (shaderObjectId == 0) {
            if (LoggerConfig.ON) {
                Log.w(TAG, "不能创建新的着色器");
            }
            return  0;
        }

        //将代码传到着色器对象中，并进行编译
        glShaderSource(shaderObjectId, shaderCode);
        glCompileShader(shaderObjectId);

        //获取编译状态
        final int[] compileStatus = new int[1];
        //传入数组，OpenGL静态方法将会把编译状态写到数组中，第4个参数0是offset，表示将结果写在数组第一位
        glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileStatus, 0);

        //获取着色器信息日志
        if (LoggerConfig.ON) {
            Log.w(TAG, "编译着色器的结果："+compileStatus[0]+"\n"+shaderCode+"\n:"+glGetShaderInfoLog(shaderObjectId));
        }

        //如果编译不通过则删除着色器
        if (compileStatus[0] == 0) {
            glDeleteShader(shaderObjectId);
            if (LoggerConfig.ON) {
                Log.w(TAG, "着色器编译失败");
            }
            return 0;
        }

        //编译着色器成功，返回着色器id，以后使用该着色器可直接调用该着色器id
        return shaderObjectId;
    }

    public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
        //创建一个新的OpenGL程序对象并将id保存起来
        final int programObjectId = glCreateProgram();

        if (programObjectId == 0) {
            if (LoggerConfig.ON) {
                Log.w(TAG, "不能创建新的OpenGL程序");
            }
            return  0;
        }

        //附上着色器
        glAttachShader(programObjectId, vertexShaderId);
        glAttachShader(programObjectId, fragmentShaderId);

        //链接程序
        glLinkProgram(programObjectId);

        //检查程序链接是否成功
        final int[] linkStatus = new int[1];
        //传入数组，OpenGL静态方法将会把链接状态写到数组中，第4个参数0是offset，表示将结果写在数组第一位
        glGetProgramiv(programObjectId, GL_LINK_STATUS, linkStatus, 0);

        //获取OpenGL程序信息日志
        if (LoggerConfig.ON) {
            Log.w(TAG, "链接OpenGL程序的结果："+linkStatus[0]+"\n:"+glGetProgramInfoLog(programObjectId));
        }

        //如果链接失败则删除OpenGL程序
        if (linkStatus[0] == 0) {
            glDeleteProgram(programObjectId);
            if (LoggerConfig.ON) {
                Log.w(TAG, "OpenGL程序链接失败");
            }
            return 0;
        }

        //链接OpenGL程序成功，返回OpenGL程序id，以后使用该改程序可直接调用该程序id
        return programObjectId;
    }

    public static boolean validateProgram(int programObjectId) {
        //评估OpenGL程序
        glValidateProgram(programObjectId);

        //获取对OpenGL评估的结果
        final int[] validateStatus = new int[1];
        //传入数组，OpenGL静态方法将会把状态写到数组中，第4个参数0是offset，表示将结果写在数组第一位
        glGetProgramiv(programObjectId, GL_VALIDATE_STATUS, validateStatus, 0);
        //获取OpenGL程序评估信息日志
        Log.w(TAG, "OpenGL程序评估的结果："+validateStatus[0]+"\n:"+glGetProgramInfoLog(programObjectId));
        return validateStatus[0] != 0;
    }

    public static int buildProgram(String vertexShaderSource, String fragmentShaderSource) {
        int program;
        int vertexShader = compileVertexShader(vertexShaderSource);
        int fragmentShader = compileFragmentShader(fragmentShaderSource);
        program = linkProgram(vertexShader, fragmentShader);

        if (LoggerConfig.ON) {
            validateProgram(program);
        }

        return program;
    }

}
